import logging
import random
import re
import time

from django.contrib.auth import authenticate
from django.core.cache import cache
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_simplejwt.tokens import RefreshToken

from users.models import User
from utils.Sms import RongLianSms

logger = logging.getLogger("django")


class LoginAPIView(APIView):
    """
    用户名/密码登录接口:
    1:接受从前端传递过来的参数(用户名和密码)
    2:验证参数是否为空
    3:验证用户名和密码是否正确
    4:验证不正确:提示用户和密码不正确
    5:验证成功:生成token.返回数据
    """

    def post(self, request):
        try:
            # 1:接受从前端传递过来的参数(用户名和密码)
            username = request.data.get("username")
            password = request.data.get("password")

            logger.info("用户名:{},密码:{}".format(username, password))

            # 2: 验证参数是否为空
            # 检查用户名和密码是否都已提供，如果其中任何一个为空则返回False
            """
            `if not all([username, password])` 和 `if not any([username, password])` 的主要区别如下：
    
            1. **all() 函数**：
               - 要求所有元素都为真时才返回 True
               - 在当前代码中，只有当 `username` 和 `password` 都非空时，`all([username, password])` 才为 True
               - `not all([username, password])` 表示只要有一个为空就为 True
               - 用于检查所有必需字段是否都已填写
    
            2. **any() 函数**：
               - 只要有一个元素为真就返回 True
               - `any([username, password])` 在任意一个变量非空时就为 True
               - `not any([username, password])` 只有在两个变量都为空时才为 True
    
            在用户登录场景中，使用 `all()` 更合适，因为我们需要确保用户名和密码两个字段都已填写，
            而不是只需要填写其中一个。
            """
            if not all([username, password]):
                logger.error("用户名或密码不能为空")
                return Response({
                    "code": 0,
                    "message": "用户名和密码不能为空"
                })

            # 3: 验证用户名和密码是否正确
            user = authenticate(username=username, password=password)

            # 4: 验证不正确:提示用户和密码不正确
            if not user:
                logger.error("用户名或密码错误")
                return Response({
                    "code": 0,
                    "message": "用户名或密码错误"
                })

            # 5: 验证正确:生成token,token 对象(签发token,续期token)
            refreshToken = RefreshToken.for_user(user)
            logger.info("登录成功-----")
            return Response({
                "code": 1,
                "message": "登录成功",
                "data": {
                    "token": str(refreshToken.access_token),  # 签发token
                    "refresh": str(refreshToken),  # 续期token
                    "username": username,
                    "userId": user.id
                }
            })
        except Exception as e:
            logger.error(e)
            logger.error("登录失败")

            return Response({
                "code": 0,
                "message": f"登录失败:{str(e)}"
            })


class SendSmsCodeAPIView(APIView):
    """发送短信验证码
    1:接受参数:手机号
    2:验证手机格式合法性 (正则) 1[3-9]\d{9}
    3:业务检验:
      3.1:验证手机号是否注册过,没有注册过 {code:0,message:手机号未注册}
      3.2:检验是否在冷却期之内(60秒不能重复发送) 11:10:45
      当前时间-上一次发送的时间>60

    4:生成验证码,发送短信,用redis记录发送时间(用于冷却期计算) 11:10:10

    """

    def post(self, request):
        try:
            # 1:接受参数:手机号
            mobile = request.data.get("mobile", "")
            scene = request.data.get("scene", "login")
            # 2:验证手机格式合法性 (正则) 1[3-9]\d{9}
            if not re.match(r'^1[3-9]\d{9}$', mobile):
                return Response({"code": 0, "message": "手机格式错误"})

            # 3:业务检验:
            if scene == "login":  # 登录场景
                # 3.1: 验证手机号是否注册过, 没有注册过{code: 0, message: 手机号未注册}
                if not User.objects.filter(phone=mobile).exists():
                    return Response({"code": 0, "message": "手机号未注册"})
            elif scene == "register":  # 注册场景
                if User.objects.filter(phone=mobile).exists():
                    return Response({"code": 0, "message": "手机号已注册"})

            # 3.2: 检验是否在冷却期之内(60秒不能重复发送)
            sms_code_last_time_key = f"code_env_spaces:users:login:last_time:{mobile}"

            last_time = cache.get(sms_code_last_time_key)
            now = time.time()

            if last_time and now - last_time < 60:
                # 计算剩余时间
                remaining = int(60 - (now - last_time))
                return Response({"code": 0, "message": f"请{remaining}秒重试"})

            # 4: 生成验证码, 发送短信, 用redis记录发送时间(用于冷却期计算)
            sms_code = ''.join(random.choices('0123456789', k=4))
            logger.info(f'短信验证码是: {sms_code}')
            sms_code_key = ""
            if scene == "login":
                # 缓存到redis
                sms_code_key = f"code_env_spaces:users:login:{mobile}"
            elif scene == "register":  # 注册场景
                sms_code_key = f"code_env_spaces:users:register:{mobile}"
            # 设置有效期300秒
            cache.set(sms_code_key, sms_code, timeout=300)

            # 模拟发送短信
            logger.info(f'给手机号: {mobile},发送短信验证码:  {sms_code}')
            rl_sms = RongLianSms()
            rl_sms.send_message(mobile,sms_code, 5)
            # 记录发送时间
            cache.set(sms_code_last_time_key, time.time(), timeout=60)
            return Response({'code': 1, 'message': '发送成功'})
        except Exception as e:
            return Response({'code': 0, 'message': '发送失败'})


class MobileLoginAPIView(APIView):
    """
    手机号+验证码的登录接口
    1:接受前端传递的参数(手机号mobile,验证码code)
    2:验证手机号的合法性
    3:验证手机号是否注册
    4:验证,用户输入的验证码code 和redis存的redis_code 是否一致,如果一致,把redis_code 删除
    5:生成token,返回token和用户信息
    """

    def post(self, request):
        try:
            # 1:接受前端传递的参数(手机号mobile,验证码code)
            mobile = request.data.get("mobile", "")
            code = request.data.get("code", "")
            # 2: 验证手机号的合法性
            if not re.match(r'^1[3-9]\d{9}$', mobile):
                return Response({"code": 0, "message": "手机格式错误"})

            # 3: 验证手机号是否注册过, 没有注册过{code: 0, message: 手机号未注册}
            if not User.objects.filter(phone=mobile).exists():
                return Response({"code": 0, "message": "手机号未注册"})

            # 4:验证,用户输入的验证码code 和redis存的redis_code 是否一致,如果一致,把redis_code 删除
            sms_code_key = f"code_env_spaces:users:login:{mobile}"
            redis_code = cache.get(sms_code_key)
            if redis_code != code:
                return Response({"code": 0, "message": "验证码错误"})

            # 验证通过, 清除缓存数据
            cache.delete(sms_code_key)
            user = User.objects.get(phone=mobile)
            refreshToken = RefreshToken.for_user(user)
            logger.info("登录成功-----")
            return Response({
                "code": 1,
                "message": "登录成功",
                "data": {
                    "token": str(refreshToken.access_token),  # 签发token
                    "refresh": str(refreshToken),  # 续期token
                    "username": user.username,
                    "userId": user.id
                }
            })



        except Exception as e:
            logger.error("登录失败--")
            return Response(data={
                "code": 0,
                "message": f"登录失败:{str(e)}",
            })


class UserRegiterAPIView(APIView):
    """
    用户注册接口

    处理用户注册请求，验证参数合法性、手机号格式与唯一性、密码强度、
    验证码有效性，并在验证通过后创建用户、签发JWT Token。

    方法:
        post(request): 接收POST请求，处理用户注册逻辑。
    """

    def post(self, request):
        """
        处理用户注册的POST请求

        参数:
            request (Request): 包含用户提交的注册信息，包括：
                - username (str): 用户名
                - password (str): 密码
                - mobile (str): 手机号
                - code (str): 短信验证码

        返回:
            Response: 注册结果响应，包含状态码、消息及用户信息或错误提示。
        """
        try:
            # 1:接受参数
            username = request.data.get("username")
            password = request.data.get("password")
            mobile = request.data.get("mobile")
            code = request.data.get("code")

            logger.info(f"开始处理用户注册请求，用户名: {username}, 手机号: {mobile}")

            # 检查是否缺少必要参数
            if not all([username, password, mobile, code]):
                logger.warning("用户注册失败：缺少必要参数")
                return Response({
                    "code": 0,
                    "errmsg": "缺少必要参数"
                })

            # 验证手机号格式是否正确
            if not re.match(r'^1[3-9]\d{9}$', mobile):
                logger.warning(f"用户注册失败：手机号格式不正确，手机号: {mobile}")
                return Response({
                    "code": 0,
                    "errmsg": "手机号格式不正确"
                })

            # 检查手机号是否已被注册
            if User.objects.filter(phone=mobile).exists():
                logger.warning(f"用户注册失败：手机号已注册，手机号: {mobile}")
                return Response({
                    "code": 0,
                    "errmsg": "手机号已注册"
                })

            # 验证密码长度是否符合要求（6~20位）
            if len(password) < 6:
                logger.warning(f"用户注册失败：密码长度不能小于6位，用户名: {username}")
                return Response({
                    "code": 0,
                    "errmsg": "密码长度不能小于6位"
                })

            if len(password) > 20:
                logger.warning(f"用户注册失败：密码长度不能大于20位，用户名: {username}")
                return Response({
                    "code": 0,
                    "errmsg": "密码长度不能大于20位"
                })

            # 验证密码是否包含数字和字母
            if not re.search(r'[0-9]', password) or not re.search(r'[a-zA-Z]', password):
                logger.warning(f"用户注册失败：密码必须包含数字和字母，用户名: {username}")
                return Response({
                    "code": 0,
                    "errmsg": "密码必须包含数字和字母"
                })

            # 从缓存中获取短信验证码并进行校验
            sms_code_key = f"code_env_spaces:users:register:{mobile}"
            redis_code = cache.get(sms_code_key)
            if not redis_code:
                logger.warning(f"用户注册失败：验证码已过期，手机号: {mobile}")
                return Response({
                    "code": 0,
                    "errmsg": "验证码已过期"
                })
            if redis_code != code:
                logger.warning(f"用户注册失败：验证码错误，手机号: {mobile}")
                return Response({
                    "code": 0,
                    "errmsg": "验证码错误"
                })

            # 创建新用户
            user = User.objects.create_user(
                username=username,
                password=password,
                phone=mobile
            )
            logger.info(f"用户创建成功，用户ID: {user.id}, 用户名: {username}")

            # 删除已使用的验证码
            cache.delete(sms_code_key)

            # 为新用户生成JWT Token
            refreshToken = RefreshToken.for_user(user)
            logger.info(f"为用户生成JWT Token成功，用户ID: {user.id}")

            # 返回注册成功响应
            logger.info(f"用户注册成功，用户ID: {user.id}, 用户名: {username}")
            return Response({
                "code": 1,
                "message": "注册成功",
                "data": {
                    "token": str(refreshToken.access_token),  # 签发token
                    "refresh": str(refreshToken),  # 续期token
                    "username": user.username,
                    "userId": user.id
                }
            })

        except Exception as e:
            # 捕获异常并返回错误信息
            logger.error(f"用户注册异常失败: {str(e)}", exc_info=True)
            return Response({
                "code": 0,
                "message": f"注册失败:{str(e)}"
            })